!**********************************************************************************************************************************
! LICENSING
! Copyright (C) 2013-2015  National Renewable Energy Laboratory
!
!    This file is part of SeaState.
!
! Licensed under the Apache License, Version 2.0 (the "License");
! you may not use this file except in compliance with the License.
! You may obtain a copy of the License at
!
!     http://www.apache.org/licenses/LICENSE-2.0
!
! Unless required by applicable law or agreed to in writing, software
! distributed under the License is distributed on an "AS IS" BASIS,
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
! See the License for the specific language governing permissions and
! limitations under the License.
!    
!**********************************************************************************************************************************
MODULE SeaState_Output

      ! This MODULE stores variables used for output.

   USE                              NWTC_Library
   USE                              SeaState_Types
   USE                              Waves ! for WaveNumber
   
   IMPLICIT                         NONE
   
   PRIVATE

   TYPE(ProgDesc), PUBLIC, PARAMETER            :: SeaSt_ProgDesc = ProgDesc( 'SeaState', '', '' )

! ===================================================================================================
! NOTE: The following lines of code were generated by a Matlab script called "Write_ChckOutLst.m"
!      using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these
!      lines should be modified in the Matlab script and/or Excel worksheet as necessary.
! ===================================================================================================
! This code was generated by "Write_ChckOutLst.m" at 07-Sep-2022 15:30:45.


     ! Indices for computing output channels:
     ! NOTES:
     !    (1) These parameters are in the order stored in "OutListParameters.xlsx"
     !    (2) Array AllOuts() must be dimensioned to the value of the largest output parameter

     !  Time:

   INTEGER(IntKi), PARAMETER      :: Time       =   0


     ! Wave Elevations:

   INTEGER(IntKi), PARAMETER      :: Wave1Elev  =   1
   INTEGER(IntKi), PARAMETER      :: Wave2Elev  =   2
   INTEGER(IntKi), PARAMETER      :: Wave3Elev  =   3
   INTEGER(IntKi), PARAMETER      :: Wave4Elev  =   4
   INTEGER(IntKi), PARAMETER      :: Wave5Elev  =   5
   INTEGER(IntKi), PARAMETER      :: Wave6Elev  =   6
   INTEGER(IntKi), PARAMETER      :: Wave7Elev  =   7
   INTEGER(IntKi), PARAMETER      :: Wave8Elev  =   8
   INTEGER(IntKi), PARAMETER      :: Wave9Elev  =   9
   INTEGER(IntKi), PARAMETER      :: Wave1Elv1  =  10
   INTEGER(IntKi), PARAMETER      :: Wave2Elv1  =  11
   INTEGER(IntKi), PARAMETER      :: Wave3Elv1  =  12
   INTEGER(IntKi), PARAMETER      :: Wave4Elv1  =  13
   INTEGER(IntKi), PARAMETER      :: Wave5Elv1  =  14
   INTEGER(IntKi), PARAMETER      :: Wave6Elv1  =  15
   INTEGER(IntKi), PARAMETER      :: Wave7Elv1  =  16
   INTEGER(IntKi), PARAMETER      :: Wave8Elv1  =  17
   INTEGER(IntKi), PARAMETER      :: Wave9Elv1  =  18
   INTEGER(IntKi), PARAMETER      :: Wave1Elv2  =  19
   INTEGER(IntKi), PARAMETER      :: Wave2Elv2  =  20
   INTEGER(IntKi), PARAMETER      :: Wave3Elv2  =  21
   INTEGER(IntKi), PARAMETER      :: Wave4Elv2  =  22
   INTEGER(IntKi), PARAMETER      :: Wave5Elv2  =  23
   INTEGER(IntKi), PARAMETER      :: Wave6Elv2  =  24
   INTEGER(IntKi), PARAMETER      :: Wave7Elv2  =  25
   INTEGER(IntKi), PARAMETER      :: Wave8Elv2  =  26
   INTEGER(IntKi), PARAMETER      :: Wave9Elv2  =  27


     ! Wave Kinematics:

   INTEGER(IntKi), PARAMETER      :: FVel1xi    =  28
   INTEGER(IntKi), PARAMETER      :: FVel2xi    =  29
   INTEGER(IntKi), PARAMETER      :: FVel3xi    =  30
   INTEGER(IntKi), PARAMETER      :: FVel4xi    =  31
   INTEGER(IntKi), PARAMETER      :: FVel5xi    =  32
   INTEGER(IntKi), PARAMETER      :: FVel6xi    =  33
   INTEGER(IntKi), PARAMETER      :: FVel7xi    =  34
   INTEGER(IntKi), PARAMETER      :: FVel8xi    =  35
   INTEGER(IntKi), PARAMETER      :: FVel9xi    =  36
   INTEGER(IntKi), PARAMETER      :: FVel1yi    =  37
   INTEGER(IntKi), PARAMETER      :: FVel2yi    =  38
   INTEGER(IntKi), PARAMETER      :: FVel3yi    =  39
   INTEGER(IntKi), PARAMETER      :: FVel4yi    =  40
   INTEGER(IntKi), PARAMETER      :: FVel5yi    =  41
   INTEGER(IntKi), PARAMETER      :: FVel6yi    =  42
   INTEGER(IntKi), PARAMETER      :: FVel7yi    =  43
   INTEGER(IntKi), PARAMETER      :: FVel8yi    =  44
   INTEGER(IntKi), PARAMETER      :: FVel9yi    =  45
   INTEGER(IntKi), PARAMETER      :: FVel1zi    =  46
   INTEGER(IntKi), PARAMETER      :: FVel2zi    =  47
   INTEGER(IntKi), PARAMETER      :: FVel3zi    =  48
   INTEGER(IntKi), PARAMETER      :: FVel4zi    =  49
   INTEGER(IntKi), PARAMETER      :: FVel5zi    =  50
   INTEGER(IntKi), PARAMETER      :: FVel6zi    =  51
   INTEGER(IntKi), PARAMETER      :: FVel7zi    =  52
   INTEGER(IntKi), PARAMETER      :: FVel8zi    =  53
   INTEGER(IntKi), PARAMETER      :: FVel9zi    =  54
   INTEGER(IntKi), PARAMETER      :: FAcc1xi    =  55
   INTEGER(IntKi), PARAMETER      :: FAcc2xi    =  56
   INTEGER(IntKi), PARAMETER      :: FAcc3xi    =  57
   INTEGER(IntKi), PARAMETER      :: FAcc4xi    =  58
   INTEGER(IntKi), PARAMETER      :: FAcc5xi    =  59
   INTEGER(IntKi), PARAMETER      :: FAcc6xi    =  60
   INTEGER(IntKi), PARAMETER      :: FAcc7xi    =  61
   INTEGER(IntKi), PARAMETER      :: FAcc8xi    =  62
   INTEGER(IntKi), PARAMETER      :: FAcc9xi    =  63
   INTEGER(IntKi), PARAMETER      :: FAcc1yi    =  64
   INTEGER(IntKi), PARAMETER      :: FAcc2yi    =  65
   INTEGER(IntKi), PARAMETER      :: FAcc3yi    =  66
   INTEGER(IntKi), PARAMETER      :: FAcc4yi    =  67
   INTEGER(IntKi), PARAMETER      :: FAcc5yi    =  68
   INTEGER(IntKi), PARAMETER      :: FAcc6yi    =  69
   INTEGER(IntKi), PARAMETER      :: FAcc7yi    =  70
   INTEGER(IntKi), PARAMETER      :: FAcc8yi    =  71
   INTEGER(IntKi), PARAMETER      :: FAcc9yi    =  72
   INTEGER(IntKi), PARAMETER      :: FAcc1zi    =  73
   INTEGER(IntKi), PARAMETER      :: FAcc2zi    =  74
   INTEGER(IntKi), PARAMETER      :: FAcc3zi    =  75
   INTEGER(IntKi), PARAMETER      :: FAcc4zi    =  76
   INTEGER(IntKi), PARAMETER      :: FAcc5zi    =  77
   INTEGER(IntKi), PARAMETER      :: FAcc6zi    =  78
   INTEGER(IntKi), PARAMETER      :: FAcc7zi    =  79
   INTEGER(IntKi), PARAMETER      :: FAcc8zi    =  80
   INTEGER(IntKi), PARAMETER      :: FAcc9zi    =  81
   INTEGER(IntKi), PARAMETER      :: FDynP1     =  82
   INTEGER(IntKi), PARAMETER      :: FDynP2     =  83
   INTEGER(IntKi), PARAMETER      :: FDynP3     =  84
   INTEGER(IntKi), PARAMETER      :: FDynP4     =  85
   INTEGER(IntKi), PARAMETER      :: FDynP5     =  86
   INTEGER(IntKi), PARAMETER      :: FDynP6     =  87
   INTEGER(IntKi), PARAMETER      :: FDynP7     =  88
   INTEGER(IntKi), PARAMETER      :: FDynP8     =  89
   INTEGER(IntKi), PARAMETER      :: FDynP9     =  90
   INTEGER(IntKi), PARAMETER      :: FAccMCF1xi =  91
   INTEGER(IntKi), PARAMETER      :: FAccMCF2xi =  92
   INTEGER(IntKi), PARAMETER      :: FAccMCF3xi =  93
   INTEGER(IntKi), PARAMETER      :: FAccMCF4xi =  94
   INTEGER(IntKi), PARAMETER      :: FAccMCF5xi =  95
   INTEGER(IntKi), PARAMETER      :: FAccMCF6xi =  96
   INTEGER(IntKi), PARAMETER      :: FAccMCF7xi =  97
   INTEGER(IntKi), PARAMETER      :: FAccMCF8xi =  98
   INTEGER(IntKi), PARAMETER      :: FAccMCF9xi =  99
   INTEGER(IntKi), PARAMETER      :: FAccMCF1yi = 100
   INTEGER(IntKi), PARAMETER      :: FAccMCF2yi = 101
   INTEGER(IntKi), PARAMETER      :: FAccMCF3yi = 102
   INTEGER(IntKi), PARAMETER      :: FAccMCF4yi = 103
   INTEGER(IntKi), PARAMETER      :: FAccMCF5yi = 104
   INTEGER(IntKi), PARAMETER      :: FAccMCF6yi = 105
   INTEGER(IntKi), PARAMETER      :: FAccMCF7yi = 106
   INTEGER(IntKi), PARAMETER      :: FAccMCF8yi = 107
   INTEGER(IntKi), PARAMETER      :: FAccMCF9yi = 108
   INTEGER(IntKi), PARAMETER      :: FAccMCF1zi = 109
   INTEGER(IntKi), PARAMETER      :: FAccMCF2zi = 110
   INTEGER(IntKi), PARAMETER      :: FAccMCF3zi = 111
   INTEGER(IntKi), PARAMETER      :: FAccMCF4zi = 112
   INTEGER(IntKi), PARAMETER      :: FAccMCF5zi = 113
   INTEGER(IntKi), PARAMETER      :: FAccMCF6zi = 114
   INTEGER(IntKi), PARAMETER      :: FAccMCF7zi = 115
   INTEGER(IntKi), PARAMETER      :: FAccMCF8zi = 116
   INTEGER(IntKi), PARAMETER      :: FAccMCF9zi = 117


     ! The maximum number of output channels which can be output by the code.
   INTEGER(IntKi), PARAMETER, PUBLIC      :: MaxOutPts  = 117

!End of code generated by Matlab script Write_ChckOutLst
! ===================================================================================================

   
   INTEGER, PARAMETER             :: WaveElevi(9)   = (/Wave1Elev,Wave2Elev,Wave3Elev,Wave4Elev,Wave5Elev,Wave6Elev,Wave7Elev,Wave8Elev,Wave9Elev/)
   INTEGER, PARAMETER             :: WaveElevi1(9)  = (/Wave1Elv1,Wave2Elv1,Wave3Elv1,Wave4Elv1,Wave5Elv1,Wave6Elv1,Wave7Elv1,Wave8Elv1,Wave9Elv1/)
   INTEGER, PARAMETER             :: WaveElevi2(9)  = (/Wave1Elv2,Wave2Elv2,Wave3Elv2,Wave4Elv2,Wave5Elv2,Wave6Elv2,Wave7Elv2,Wave8Elv2,Wave9Elv2/)

   INTEGER, PARAMETER             :: FVel(3,9) = reshape((/FVel1xi,FVel1yi,FVel1zi, &
                                                              FVel2xi,FVel2yi,FVel2zi, &
                                                              FVel3xi,FVel3yi,FVel3zi, &
                                                              FVel4xi,FVel4yi,FVel4zi, &
                                                              FVel5xi,FVel5yi,FVel5zi, &
                                                              FVel6xi,FVel6yi,FVel6zi, &
                                                              FVel7xi,FVel7yi,FVel7zi, &
                                                              FVel8xi,FVel8yi,FVel8zi, &
                                                              FVel9xi,FVel9yi,FVel9zi/), &
                                                              (/3,9/))
   INTEGER, PARAMETER             :: FAcc(3,9) = reshape((/FAcc1xi,FAcc1yi,FAcc1zi, &
                                                              FAcc2xi,FAcc2yi,FAcc2zi, &
                                                              FAcc3xi,FAcc3yi,FAcc3zi, &
                                                              FAcc4xi,FAcc4yi,FAcc4zi, &
                                                              FAcc5xi,FAcc5yi,FAcc5zi, &
                                                              FAcc6xi,FAcc6yi,FAcc6zi, &
                                                              FAcc7xi,FAcc7yi,FAcc7zi, &
                                                              FAcc8xi,FAcc8yi,FAcc8zi, &
                                                              FAcc9xi,FAcc9yi,FAcc9zi/), &
                                                              (/3,9/)) 
  INTEGER, PARAMETER             :: FDynP(9)   = (/FDynP1,FDynP2,FDynP3,FDynP4,FDynP5,FDynP6,FDynP7,FDynP8,FDynP9/)
  INTEGER, PARAMETER             :: FAccMCF(3,9) = reshape((/FAccMCF1xi,FAccMCF1yi,FAccMCF1zi, &
                                                             FAccMCF2xi,FAccMCF2yi,FAccMCF2zi, &
                                                             FAccMCF3xi,FAccMCF3yi,FAccMCF3zi, &
                                                             FAccMCF4xi,FAccMCF4yi,FAccMCF4zi, &
                                                             FAccMCF5xi,FAccMCF5yi,FAccMCF5zi, &
                                                             FAccMCF6xi,FAccMCF6yi,FAccMCF6zi, &
                                                             FAccMCF7xi,FAccMCF7yi,FAccMCF7zi, &
                                                             FAccMCF8xi,FAccMCF8yi,FAccMCF8zi, &
                                                             FAccMCF9xi,FAccMCF9yi,FAccMCF9zi/), &
                                                             (/3,9/)) 
  
   
      ! ..... Public Subroutines ...................................................................................................
   PUBLIC :: SeaStOut_WrSummaryFile
   PUBLIC :: SeaStOut_MapOutputs
   PUBLIC :: SeaStOut_WriteOutputs
   PUBLIC :: SeaStOut_OpenOutput
   PUBLIC :: SeaStOut_CloseOutput
   PUBLIC :: SeaStOut_Init
   PUBLIC :: SeaStOut_WriteWvKinFiles
   PUBLIC :: SeaStOut_WriteWaveElev0
   
CONTAINS

!====================================================================================================
SUBROUTINE SeaStOut_WriteWvKinFiles( Rootname, SeaSt_Prog, WaveField, WaveDT, X_HalfWidth, Y_HalfWidth, &
                                     deltaGrid, NGrid, ErrStat, ErrMsg )

      ! Passed variables
   CHARACTER(*),                  INTENT( IN    )   :: Rootname             ! filename including full path, minus any file extension.
   TYPE(ProgDesc),                INTENT( IN    )   :: SeaSt_Prog           ! the name/version/date of the SeaState program
   TYPE(SeaSt_WaveFieldType),     INTENT( IN    )   :: WaveField            !< WaveFieldType
   real(DbKi),                    intent( in    )   :: WaveDT
   real(ReKi),                    intent( in    )   :: X_HalfWidth
   real(ReKi),                    intent( in    )   :: Y_HalfWidth
   real(ReKi),                    intent( in    )   :: deltaGrid(3)
   INTEGER,                       INTENT( IN    )   :: NGrid(3)             ! Number of grid points for the wave kinematics arrays
   INTEGER,                       INTENT(   OUT )   :: ErrStat              ! returns a non-zero value when an error occurs  
   CHARACTER(*),                  INTENT(   OUT )   :: ErrMsg               ! Error message if ErrStat /= ErrID_None
      
      ! Local variables
   INTEGER                                    :: UnWv                       ! file unit for writing the various wave kinematics files
   CHARACTER(1024)                            :: WvName                     ! complete filename for one of the output files
   CHARACTER(5)                               :: extension(7)     
   INTEGER                                    :: i, j, k, m, iFile
   CHARACTER(64)                              :: Frmt, Sfrmt
   CHARACTER(1), parameter                    :: Delim = " "
   real(ReKi)                                 :: x_gridPts(NGrid(1)), y_gridPts(NGrid(2)), z_gridPts(NGrid(3))
      ! Initialize ErrStat      
   ErrStat = ErrID_None         
   ErrMsg  = ""       
      
   extension  = (/'.Vxi ','.Vyi ','.Vzi ','.Axi ','.Ayi ','.Azi ','.DynP'/)
   !Frmt = '('//TRIM(Int2LStr(NNodes))//'(:,A,ES11.4e2))'
   Frmt  = '(A1,ES11.4e2)'
   Sfrmt = '(A1,A11)'
   
   ! Create grid point locations

   do i = 0, NGrid(1)-1
      x_gridPts(i+1) = -X_HalfWidth + deltaGrid(1)*i
   end do
   do i = 0, NGrid(2)-1
      y_gridPts(i+1) = -Y_HalfWidth + deltaGrid(2)*i
   end do
   do i = 0, NGrid(3)-1
      z_gridPts(i+1) =  - ( 1.0 - cos( real((NGrid(3) - 1) - i, ReKi) * deltaGrid(3) )  ) * WaveField%GridParams%Z_Depth
   end do
   
   ! Write the increments from [0, NStepWave] even though for OpenFAST data, NStepWave = 0, but for arbitrary user data this may not be true.
   ! As a result for WaveMod=5,6 we shouldn't assume periodic waves over the period WaveTMax
   
   DO iFile = 1,7
      

      WvName = TRIM(Rootname) // TRIM(extension(iFile))
      !$OMP critical(fileopen_critical)
      CALL GetNewUnit( UnWv )
      CALL OpenFOutFile ( UnWv, WvName, ErrStat, ErrMsg ) 
      !$OMP end critical(fileopen_critical)
         IF (ErrStat >=AbortErrLev) RETURN
      
      call WriteWvKinHeader( UnWv, iFile, Delim, SeaSt_Prog, waveDT, -z_gridPts(1), NGrid, deltaGrid )
   
      DO m= 0,WaveField%NStepWave
         DO k = 1, NGrid(3)
            do j = 1, NGrid(2)
               do i = 1, NGrid(1)
                  
            !IF ( nodeInWater(i,j) == 0 )  THEN
            !   WRITE(UnWv,Sfrmt,ADVANCE='no')   Delim,  '##########'
            !ELSE
                  
                  SELECT CASE (iFile)
                     CASE (1)              
                        WRITE(UnWv,Frmt,ADVANCE='no')   Delim,  WaveField%WaveVel (m,i,j,k,1)  
                     CASE (2)              
                        WRITE(UnWv,Frmt,ADVANCE='no')   Delim,  WaveField%WaveVel (m,i,j,k,2)  
                     CASE (3)              
                        WRITE(UnWv,Frmt,ADVANCE='no')   Delim,  WaveField%WaveVel (m,i,j,k,3)  
                     CASE (4)              
                        WRITE(UnWv,Frmt,ADVANCE='no')   Delim,  WaveField%WaveAcc (m,i,j,k,1) 
                     CASE (5)              
                        WRITE(UnWv,Frmt,ADVANCE='no')   Delim,  WaveField%WaveAcc (m,i,j,k,2) 
                     CASE (6)              
                        WRITE(UnWv,Frmt,ADVANCE='no')   Delim,  WaveField%WaveAcc (m,i,j,k,3) 
                     CASE (7)              
                        WRITE(UnWv,Frmt,ADVANCE='no')   Delim,  WaveField%WaveDynP(m,i,j,k  )  
                  END SELECT
            !END IF
               END DO  ! for i
               WRITE (UnWv,'(A)', IOSTAT=ErrStat)   ' ! All X grid locations at Y = '//TRIM(num2lstr(y_gridPts(j)))// &
                                                   ', Z = '//TRIM(num2lstr(z_gridPts(k)))// &
                                                   ', WaveTime =  '//TRIM(num2lstr(waveDT*m))      ! write the line return   
            END DO  ! for j
         END DO  ! for k
      END DO  ! for m
      CLOSE( UnWv, IOSTAT=ErrStat )
      IF (ErrStat /= 0) THEN
         ErrStat = ErrID_Fatal
         ErrMsg  = 'Problem closing wave kinematics file'
         RETURN
      END IF      
   END DO
   
   ! WaveElevation Grid
   WvName = TRIM(Rootname) // '.Elev'
   !$OMP critical(fileopen_critical)
   CALL GetNewUnit( UnWv )
   CALL OpenFOutFile ( UnWv, WvName, ErrStat, ErrMsg ) 
   !$OMP end critical(fileopen_critical)
      IF (ErrStat >=AbortErrLev) RETURN
      
      
  call WriteWvKinHeader( UnWv, 8, Delim, SeaSt_Prog, waveDT, -z_gridPts(1), NGrid, deltaGrid )
   
   
   DO m= 0,WaveField%NStepWave
      do j = 1, NGrid(2)
         do i = 1, NGrid(1)   
            if ( allocated(WaveField%WaveElev2) ) then
               WRITE(UnWv,Frmt,ADVANCE='no')   Delim,  WaveField%WaveElev1(m,i,j) + WaveField%WaveElev2(m,i,j)
            else
               WRITE(UnWv,Frmt,ADVANCE='no')   Delim,  WaveField%WaveElev1(m,i,j)
            end if
         end do
         WRITE (UnWv,'()', IOSTAT=ErrStat)          ! write the line return 
      end do
      
   END DO
      
   CLOSE( UnWv, IOSTAT=ErrStat )
   IF (ErrStat /= 0) THEN
      ErrStat = ErrID_Fatal
      ErrMsg  = 'Problem closing wave elevations file'
      RETURN
   END IF     
      
   contains
   
   subroutine WriteWvKinHeader( UnWv, fileType, Delim, SeaSt_Prog, waveDT, Z_Depth, NGrid, deltaGrid )
            ! Passed variables
      INTEGER,                       INTENT( IN    )   :: UnWv
      integer,                       intent( in    )   :: fileType
      CHARACTER(*),                  intent( in    )   :: Delim
      TYPE(ProgDesc),                INTENT( IN    )   :: SeaSt_Prog           ! the name/version/date of the SeaState program
      real(DbKi),                    intent( in    )   :: WaveDT
      real(ReKi),                    intent( in    )   :: Z_Depth
      real(ReKi),                    intent( in    )   :: deltaGrid(3)
      INTEGER,                       INTENT( IN    )   :: NGrid(3)             ! Number of grid points for the wave kinematics arrays

      integer(IntKi)               :: i
      CHARACTER(64)                :: Frmt, Frmt2
      
            ! Write the summary file header    
     ! WRITE (UnWv,'(/,A/)', IOSTAT=ErrStat)  'This wave kinematics file was generated by '//TRIM( HD_Prog%Name )//&
      WRITE (UnWv,'(A)', IOSTAT=ErrStat)  'This wave kinematics file was generated by '//TRIM( SeaSt_Prog%Name )//&
                        ' '//TRIM( SeaSt_Prog%Ver )//' on '//CurDate()//' at '//CurTime()//'.'
      SELECT CASE (fileType)
         CASE (1)              
            WRITE(UnWv, '(A)',  IOSTAT=ErrStat)   'Fluid Velocity along the X-direction (m/s)'
         CASE (2)              
            WRITE(UnWv, '(A)',  IOSTAT=ErrStat)   'Fluid Velocity along the Y-direction (m/s)'
         CASE (3)              
            WRITE(UnWv, '(A)',  IOSTAT=ErrStat)   'Fluid Velocity along the Z-direction (m/s)'
         CASE (4)              
            WRITE(UnWv, '(A)',  IOSTAT=ErrStat)   'Fluid Acceleration along the X-direction (m/s^2)'
         CASE (5)              
            WRITE(UnWv, '(A)',  IOSTAT=ErrStat)   'Fluid Acceleration along the Y-direction (m/s^2)'
         CASE (6)              
            WRITE(UnWv, '(A)',  IOSTAT=ErrStat)   'Fluid Acceleration along the Z-direction (m/s^2)'
         CASE (7)              
            WRITE(UnWv, '(A)',  IOSTAT=ErrStat)   'Fluid Dynamic Pressure (Pa)'
         CASE (8)
            WRITE(UnWv, '(A)',  IOSTAT=ErrStat)   'Wave Elevation (m)'
      END SELECT
      Frmt = '(A1,ES11.4e2,A)'
      Frmt2 = '(A1,I11,A)'
      write (UnWv,Frmt,  IOSTAT=ErrStat)  '!' ,  waveDT         , '  - WaveDT (s)'
      write (UnWv,Frmt2,  IOSTAT=ErrStat)  '!' ,  NGrid(1)       , '  - Number of X grid points [NX*2 - 1]'
      write (UnWv,Frmt2,  IOSTAT=ErrStat)  '!' ,  NGrid(2)       , '  - Number of Y grid points [NY*2 - 1]'
      write (UnWv,Frmt2,  IOSTAT=ErrStat)  '!' ,  NGrid(3)       , '  - Number of Z grid points [NZ]'
      write (UnWv,Frmt,  IOSTAT=ErrStat)  '!' ,  deltaGrid(1)   , '  - X grid spacing (m) [dX]'
      write (UnWv,Frmt,  IOSTAT=ErrStat)  '!' ,  deltaGrid(2)   , '  - Y grid spacing (m) [dY]'
      write (UnWv,Frmt,  IOSTAT=ErrStat)  '!' ,  Z_Depth        , '  - Lowest Z Depth (m) [Z_Depth]'
      write (UnWv,Frmt,  IOSTAT=ErrStat)  '!' ,  deltaGrid(3)   , '  - Z grid spacing (radians) [dthetaZ, where Z coordinates are found using: Z[nZ] = ( COS( nZ*dthetaZ ) - 1 )*Z_Depth, where nZ = {NZ-1, NZ-2, ..., 1,0} and dthetaZ = pi/( 2*(NZ-1) ) and 0 < Z_Depth <= WtrDpth+MSL2SWL ]'

      Frmt = '(A1,'//TRIM(Int2LStr(NGrid(1)))//'(A1,ES11.4e2),A)'
      write(UnWv,Frmt)   '!', ( Delim,  x_gridPts(i)  , i=1,NGrid(1) ), ' - X-Locations (m)'
      Frmt = '(A1,'//TRIM(Int2LStr(NGrid(2)))//'(A1,ES11.4e2),A)'
      write(UnWv,Frmt)   '!', ( Delim,  y_gridPts(i)  , i=1,NGrid(2) ), ' - Y-Locations (m)'
      Frmt = '(A1,'//TRIM(Int2LStr(NGrid(3)))//'(A1,ES11.4e2),A)'
      write(UnWv,Frmt)   '!', ( Delim,  z_gridPts(i)  , i=1,NGrid(3) ), ' - Z-Locations (m)'
   end subroutine WriteWvKinHeader
   
   
END SUBROUTINE SeaStOut_WriteWvKinFiles 
subroutine SeaStOut_WriteWaveElev0( Rootname, NStepWave, NGrid, WaveElev1, WaveElev2, WaveTime, ErrStat, ErrMsg )

      ! Passed variables
   CHARACTER(*),                  INTENT( IN    )   :: Rootname             ! filename including full path, minus any file extension.
   INTEGER,                       INTENT( IN    )   :: NStepWave            ! Number of time steps for the wave kinematics arrays
   INTEGER,                       INTENT( IN    )   :: NGrid(3)             ! Number of grid points for the wave kinematics arrays
   REAL(SiKi), allocatable,       INTENT( IN    )   :: WaveElev1 (:,:,: )   ! Instantaneous wave elevations at requested locations - 1st order
   REAL(SiKi), allocatable,       INTENT( IN    )   :: WaveElev2 (:,:,: )   ! Instantaneous wave elevations at requested locations - 2nd order
   REAL(SiKi), allocatable,       INTENT( IN    )   :: WaveTime (:    )     ! The time values for the wave kinematics  (time)
   INTEGER,                       INTENT(   OUT )   :: ErrStat              ! returns a non-zero value when an error occurs  
   CHARACTER(*),                  INTENT(   OUT )   :: ErrMsg               ! Error message if ErrStat /= ErrID_None
      
      ! Local variables
   INTEGER                                    :: UnWv                       ! file unit for writing the various wave kinematics files
   CHARACTER(1024)                            :: WvName                     ! complete filename for one of the output files
   INTEGER                                    :: i, j, m
   CHARACTER(64)                              :: Frmt, Frmt2

   ! Initialize ErrStat      
   ErrStat = ErrID_None         
   ErrMsg  = "" 
   Frmt = '(F12.4,ES12.4e2)'
   Frmt2 = '(2(A12))'

      
   WvName = TRIM(Rootname) // '.Elev'
   i = NGrid(1) / 2 + 1 
   j = NGrid(2) / 2 + 1 
   !$OMP critical(fileopen_critical)
   CALL GetNewUnit( UnWv )
   CALL OpenFOutFile ( UnWv, WvName, ErrStat, ErrMsg ) 
   !$OMP end critical(fileopen_critical)
      IF (ErrStat >=AbortErrLev) RETURN
  ! WRITE (UnWv,'(A)', IOSTAT=ErrStat)  'This wave elevation (0,0) file was generated by '//TRIM( SeaSt_Prog%Name )//&
  !                      ' '//TRIM( SeaSt_Prog%Ver )//' on '//CurDate()//' at '//CurTime()//'.'
   WRITE (UnWv,Frmt2, IOSTAT=ErrStat)  'Time', 'WaveElev0'
   ! Write the increments from [0, NStepWave] even though for OpenFAST data, NStepWave = 0, but for arbitrary user data this may not be true.
   ! As a result for WaveMod=5,6 we shouldn't assume periodic waves over the period WaveTMax
   DO m= 0,NStepWave
      if ( allocated(WaveElev2) ) then
         WRITE(UnWv,Frmt)   WaveTime(m), WaveElev1(m,i,j) + WaveElev2(m,i,j)
      else
         WRITE(UnWv,Frmt)   WaveTime(m), WaveElev1(m,i,j)
      end if 
   END DO
      
   CLOSE( UnWv, IOSTAT=ErrStat )
   IF (ErrStat /= 0) THEN
      ErrStat = ErrID_Fatal
      ErrMsg  = 'Problem closing wave elevations file'
      RETURN
   END IF   
end subroutine SeaStOut_WriteWaveElev0

!====================================================================================================
subroutine SeaStOut_MapOutputs(  p, WaveElev, WaveElev1, WaveElev2, WaveVel, WaveAcc, WaveAccMCF, WaveDynP, AllOuts, ErrStat, ErrMsg )
! This subroutine writes the data stored in the y variable to the correct indexed postions in WriteOutput
! This is called by SeaSt_CalcOutput() at each time step.
!---------------------------------------------------------------------------------------------------- 
   TYPE(SeaSt_ParameterType),          intent( in    )  :: p              ! SeaState's parameter data
   REAL(SiKi),                         intent( in    )  :: WaveElev(:)    ! Instantaneous total elevation of incident waves at each of the NWaveElev points where the incident wave elevations can be output (meters)   
   REAL(SiKi),                         intent( in    )  :: WaveElev1(:)   ! Instantaneous first order elevation of incident waves at each of the NWaveElev points where the incident wave elevations can be output (meters)   
   REAL(SiKi),                         intent( in    )  :: WaveElev2(:)   ! Instantaneous second order elevation of incident waves at each of the NWaveElev points where the incident wave elevations can be output (meters)   
   REAL(SiKi),                         intent( in    )  :: WaveVel(:,:)   ! Instantaneous total elevation of incident waves at each of the NWaveElev points where the incident wave elevations can be output (meters)   
   REAL(SiKi),                         intent( in    )  :: WaveAcc(:,:)   ! Instantaneous first order elevation of incident waves at each of the NWaveElev points where the incident wave elevations can be output (meters)   
   REAL(SiKi),                         intent( in    )  :: WaveAccMCF(:,:) ! Instantaneous first order elevation of incident waves at each of the NWaveElev points where the incident wave elevations can be output (meters)   
   REAL(SiKi),                         intent( in    )  :: WaveDynP(:)    ! Instantaneous second order elevation of incident waves at each of the NWaveElev points where the incident wave elevations can be output (meters)   
   REAL(ReKi),                         intent(   out )  :: AllOuts(MaxOutpts)
   INTEGER(IntKi),                     intent(   out )  :: ErrStat        ! Error status of the operation
   CHARACTER(*),                       intent(   out )  :: ErrMsg         ! Error message if ErrStat /= ErrID_None

   integer                                              :: I
!   integer(IntKi)                                       :: ErrStat2
!   character(ErrMsgLen)                                 :: ErrMsg2
  
   ErrStat = ErrID_None
   ErrMsg = ""
   
   ! Initialize all unused channels to zero (in case they don't get set, but are still requested)
   AllOuts  = 0.0_ReKi

   do I=1,p%NWaveElev
      AllOuts(WaveElevi(I)) = WaveElev(I)
      AllOuts(WaveElevi1(I))= WaveElev1(I)
      AllOuts(WaveElevi2(I))= WaveElev2(I)
   end do
   
   do I=1,p%NWaveKin
      AllOuts(FVel(:,I)) = WaveVel(1:3,I)
      AllOuts(FAcc(:,I))= WaveAcc(1:3,I)
      AllOuts(FDynP(I))= WaveDynP(I)
      AllOuts(FAccMCF(:,I))= WaveAccMCF(1:3,I)
   end do
   
   
end subroutine SeaStOut_MapOutputs

!====================================================================================================
SUBROUTINE SeaStOut_WriteOutputs( Time, y, p, Decimate, ErrStat, ErrMsg )
! This subroutine writes the data stored in WriteOutputs (and indexed in OutParam) to the file
! opened in SeaStOut_Init()
!---------------------------------------------------------------------------------------------------- 

      ! Passed variables    
   REAL(DbKi),                   INTENT( IN    ) :: Time
   TYPE(SeaSt_OutputType),    INTENT( INOUT ) :: y                    ! SeaState's output data
   TYPE(SeaSt_ParameterType), INTENT( IN    ) :: p                    ! SeaState parameter data
   INTEGER,                      INTENT( INOUT ) :: Decimate             ! Output decimatation counter
   INTEGER,                      INTENT(   OUT ) :: ErrStat              ! returns a non-zero value when an error occurs  
   CHARACTER(*),                 INTENT(   OUT ) :: ErrMsg               ! Error message if ErrStat /= ErrID_None
   
      ! Local variables
   INTEGER                                :: I                           ! Generic loop counter
   CHARACTER(200)                         :: Frmt                        ! a string to hold a format statement
   
   
  IF (p%UnOutFile < 0 ) RETURN
  
      ! Initialize ErrStat and determine if it makes any sense to write output
!TODO: We should not have this check here, once per timestep!  This should be resolved during initialization. GJH 7/7/2014    
   IF (  .NOT. ALLOCATED( p%OutParam )  )  THEN
      ErrStat = ErrID_Warn
      ErrMsg  = ' Cannot write output to file because there are not a valid output list.'
      RETURN
   ELSE
      ErrStat = ErrID_None
      ErrMsg  = ''
   END IF
   
   
      ! Write the output parameters to the file
      
   !Frmt = '(F8.3,'//TRIM(Int2LStr(p%WAMIT%NumOuts+p%Morison%NumOuts))//'(:,A,'//TRIM( p%OutFmt )//'))'
   !Frmt = '('//TRIM( p%OutFmt )//','//TRIM(Int2LStr(p%NumOuts))//'(:,A,'//TRIM( p%OutFmt )//'))'
   
   !WRITE(p%UnOutFile,Frmt) Time, ( p%Delim, y%WAMIT%WriteOutput(I), I=1,p%WAMIT%NumOuts), ( p%Delim, y%Morison%WriteOutput(I), I=1,p%Morison%NumOuts)
   
   IF ((Decimate .EQ. p%OutDec) .OR. (Decimate .EQ. 0))  THEN
      
      Decimate = 1  !reset counter  
!TODO: Fix formatting            
      Frmt = '(F10.4)'
   
      WRITE(p%UnOutFile,Frmt,ADVANCE='no')  Time
      
      IF ( p%NumOuts > 0 ) THEN
         Frmt = '('//TRIM(Int2LStr(p%NumOuts))//'(:,A,'//TRIM( p%OutFmt )//'))'
         WRITE(p%UnOutFile,Frmt,ADVANCE='no')   ( p%Delim,  y%WriteOutput(I)  , I=1,p%NumOuts )   
      END IF
          
      WRITE (p%UnOutFile,'()', IOSTAT=ErrStat)          ! write the line return
   
   ELSE      
      Decimate = Decimate + 1
   ENDIF
   
   RETURN
   
END SUBROUTINE SeaStOut_WriteOutputs

!====================================================================================================
SUBROUTINE SeaStOut_Init( SeaSt_ProgDesc, OutRootName, InputFileData, y,  p, m, InitOut, ErrStat, ErrMsg )
! This subroutine initialized the output module, checking if the output parameter list (OutList)
! contains valid names, and opening the output file if there are any requested outputs
! NOTE: This routine must be called only after any sub-modules OUT_Init() subroutines have been called.
!----------------------------------------------------------------------------------------------------

   

      ! Passed variables

   TYPE(ProgDesc),                INTENT( IN    ) :: SeaSt_ProgDesc    ! 
   CHARACTER(*),                  INTENT( IN    ) :: OutRootName          ! The name of the output file 
   TYPE(SeaSt_InputFile ),        INTENT( IN    ) :: InputFileData        ! data needed to initialize the output module     
   TYPE(SeaSt_OutputType),        INTENT( INOUT ) :: y                    ! This module's internal data
   TYPE(SeaSt_ParameterType),     INTENT( INOUT ) :: p 
   TYPE(SeaSt_MiscVarType),       INTENT( INOUT ) :: m
   TYPE(SeaSt_InitOutputType),    INTENT( INOUT ) :: InitOut
   INTEGER,                       INTENT(   OUT ) :: ErrStat              ! a non-zero value indicates an error occurred           
   CHARACTER(*),                  INTENT(   OUT ) :: ErrMsg               ! Error message if ErrStat /= ErrID_None
   
      ! Local variables
   INTEGER                                        :: I                    ! Generic loop counter      
   INTEGER                                        :: J                    ! Generic loop counter      
   
   
   
   
   
   !-------------------------------------------------------------------------------------------------      
   ! Initialize local variables
   !-------------------------------------------------------------------------------------------------      
     
         
   ErrStat = ErrID_None         
   ErrMsg  = ""  


   !-------------------------------------------------------------------------------------------------      
   ! Check that the variables in OutList are valid      
   !-------------------------------------------------------------------------------------------------      
      
   CALL SetOutParam(InputFileData%OutList, p, ErrStat, ErrMsg )
   IF ( ErrStat >= AbortErrLev ) RETURN

   ! Aggregate the sub-module initialization outputs for the glue code

   m%LastOutTime  = 0.0_DbKi
   m%Decimate     = 0
   p%OutDec       = 1             !TODO: Remove this once the parameter has been added to the HD input file GJH 7/8/2014

   
      ! Allocate the aggregate arrays
   
   ALLOCATE ( InitOut%WriteOutputHdr ( p%NumOuts ) , STAT=ErrStat )
   IF ( ErrStat /= 0 )  THEN
      ErrMsg  = ' Error allocating memory for the WriteOutputHdr array.'
      ErrStat = ErrID_Fatal
      RETURN
   END IF
   
   ALLOCATE ( InitOut%WriteOutputUnt ( p%NumOuts ) , STAT=ErrStat )
   IF ( ErrStat /= 0 )  THEN
      ErrMsg  = ' Error allocating memory for the WriteOutputUnt array.'
      ErrStat = ErrID_Fatal
      RETURN
   END IF
   
   ALLOCATE ( y%WriteOutput         ( p%NumOuts ) , STAT=ErrStat )
   IF ( ErrStat /= 0 )  THEN
      ErrMsg  = ' Error allocating memory for the WriteOutput array.'
      ErrStat = ErrID_Fatal
      RETURN
   END IF
   y%WriteOutput = 0.0_ReKi  ! If there is an error at initialization, y%WriteOutput can be written in the SeaState_End() routine, so this needs some initial value.
   
            
      ! Initialize the HD-level Hdr and Unt elements
   DO I = 1,p%NumOuts
   
      InitOut%WriteOutputHdr(I) = TRIM( p%OutParam(I)%Name  )
      InitOut%WriteOutputUnt(I) = TRIM( p%OutParam(I)%Units )      
   
   END DO    
      
      
   J = p%NumOuts + 1
      

   IF ( p%OutSwtch == 1 .OR. p%OutSwtch == 3 ) THEN
      CALL SeaStOut_OpenOutput( SeaSt_ProgDesc, OutRootName, p, InitOut, ErrStat, ErrMsg )
      IF (ErrStat >= AbortErrLev ) RETURN
   END IF
      
      

   RETURN

END SUBROUTINE SeaStOUT_Init

!====================================================================================================
SUBROUTINE SeaStOut_OpenOutput( SeaSt_ProgDesc, OutRootName,  p, InitOut, ErrStat, ErrMsg )
! This subroutine initialized the output module, checking if the output parameter list (OutList)
! contains valid names, and opening the output file if there are any requested outputs
!----------------------------------------------------------------------------------------------------

   

      ! Passed variables

   TYPE(ProgDesc)               , INTENT( IN    ) :: SeaSt_ProgDesc
   CHARACTER(*),                  INTENT( IN    ) :: OutRootName          ! Root name for the output file
   TYPE(SeaSt_ParameterType),     INTENT( INOUT ) :: p   
   TYPE(SeaSt_InitOutPutType ),   INTENT( IN    ) :: InitOut              !
   INTEGER,                       INTENT(   OUT ) :: ErrStat              ! a non-zero value indicates an error occurred           
   CHARACTER(*),                  INTENT(   OUT ) :: ErrMsg               ! Error message if ErrStat /= ErrID_None
   
      ! Local variables
   INTEGER                                        :: I                    ! Generic loop counter      
!   INTEGER                                        :: Indx                 ! Counts the current index into the WaveKinNd array
   CHARACTER(1024)                                ::  OutFileName         ! The name of the output file  including the full path.
   CHARACTER(200)                                 :: Frmt                 ! a string to hold a format statement
                
   !-------------------------------------------------------------------------------------------------      
   ! Initialize local variables
   !-------------------------------------------------------------------------------------------------      
   ErrStat = ErrID_None
   ErrMsg = ""
      
   
   
   !-------------------------------------------------------------------------------------------------      
   ! Open the output file, if necessary, and write the header
   !-------------------------------------------------------------------------------------------------      
   p%UnOutFile = -1
   IF ( ALLOCATED( p%OutParam ) .AND. p%NumOuts > 0  ) THEN           ! Output has been requested so let's open an output file            
      
         ! Open the file for output
      OutFileName = TRIM(OutRootName)//'.out'
 
      !$OMP critical(fileopen_critical)
      CALL GetNewUnit( p%UnOutFile )
      CALL OpenFOutFile ( p%UnOutFile, OutFileName, ErrStat, ErrMsg ) 
      !$OMP end critical(fileopen_critical)
      IF (ErrStat >=AbortErrLev) RETURN
      
      
         ! Write the output file header
      
      WRITE (p%UnOutFile,'(/,A/)', IOSTAT=ErrStat)  'These predictions were generated by '//TRIM(SeaSt_ProgDesc%Name)//&
                      ' on '//CurDate()//' at '//CurTime()//'.'

         ! Write three empty lines
      WRITE (p%UnOutFile,'()', IOSTAT=ErrStat)
      WRITE (p%UnOutFile,'()', IOSTAT=ErrStat)
      WRITE (p%UnOutFile,'()', IOSTAT=ErrStat)

         ! Write the names of the output parameters:
      Frmt = '(A10)'
      WRITE(p%UnOutFile,Frmt,ADVANCE='no')  TRIM( 'Time' )
      
      IF (ALLOCATED( p%OutParam ) .AND. p%NumOuts > 0) THEN
         Frmt = '('//TRIM(Int2LStr(p%NumOuts))//'(:,A,'//TRIM( p%OutSFmt )//'))'
         WRITE(p%UnOutFile,Frmt,ADVANCE='no')   ( p%Delim, TRIM( InitOut%WriteOutputHdr(I)   ), I=1,p%NumOuts ) !since p%OutSFmt is a user-specified format, we should probably add some error handling here...
      END IF
      
      WRITE (p%UnOutFile,'()', IOSTAT=ErrStat)          ! write the line return
      

         ! Write the units of the output parameters:
         
     
      Frmt = '(A8)'
      WRITE(p%UnOutFile,Frmt,ADVANCE='no')  TRIM( '(sec)' )
      
      IF (ALLOCATED( p%OutParam ) .AND. p%NumOuts > 0) THEN
         Frmt = '('//TRIM(Int2LStr(p%NumOuts))//'(:,A,'//TRIM( p%OutSFmt )//'))'
         WRITE(p%UnOutFile,Frmt,ADVANCE='no')   ( p%Delim, TRIM( InitOut%WriteOutputUnt(I)   ), I=1,p%NumOuts ) !since p%OutSFmt is a user-specified format, we should probably add some error handling here...
      END IF

      
      WRITE (p%UnOutFile,'()', IOSTAT=ErrStat)          ! write the line return                               
      
   
      
   END IF   ! there are any requested outputs   

   RETURN

END SUBROUTINE SeaStOut_OpenOutput

!====================================================================================================
! NOTE: The following lines of code were generated by a Matlab script called "Write_ChckOutLst.m"
!      using the parameters listed in the "OutListParameters.xlsx" Excel file. Any changes to these 
!      lines should be modified in the Matlab script and/or Excel worksheet as necessary. 
!----------------------------------------------------------------------------------------------------------------------------------
!> This routine checks to see if any requested output channel names (stored in the OutList(:)) are invalid. It returns a 
!! warning if any of the channels are not available outputs from the module.
!!  It assigns the settings for OutParam(:) (i.e, the index, name, and units of the output channels, WriteOutput(:)).
!!  the sign is set to 0 if the channel is invalid.
!! It sets assumes the value p%NumOuts has been set before this routine has been called, and it sets the values of p%OutParam here.
!! 
!! This routine was generated by Write_ChckOutLst.m using the parameters listed in OutListParameters.xlsx at 07-Sep-2022 16:06:37.
SUBROUTINE SetOutParam(OutList, p, ErrStat, ErrMsg )
!..................................................................................................................................

   IMPLICIT                        NONE

      ! Passed variables

   CHARACTER(ChanLen),        INTENT(IN)     :: OutList(:)                        !< The list out user-requested outputs
   TYPE(SeaSt_ParameterType), INTENT(INOUT)  :: p                                 !< The module parameters
   INTEGER(IntKi),            INTENT(OUT)    :: ErrStat                           !< The error status code
   CHARACTER(*),              INTENT(OUT)    :: ErrMsg                            !< The error message, if an error occurred

      ! Local variables

   INTEGER                      :: ErrStat2                                        ! temporary (local) error status
   INTEGER                      :: I                                               ! Generic loop-counting index
!  INTEGER                      :: J                                               ! Generic loop-counting index
   INTEGER                      :: INDX                                            ! Index for valid arrays

   LOGICAL                      :: InvalidOutput(0:MaxOutPts)                      ! This array determines if the output channel is valid for this configuration
   CHARACTER(*), PARAMETER      :: RoutineName = "SetOutParam"

   CHARACTER(OutStrLenM1), PARAMETER  :: ValidParamAry(117) =  (/  &   ! This lists the names of the allowed parameters, which must be sorted alphabetically
                               "FACC1XI   ","FACC1YI   ","FACC1ZI   ","FACC2XI   ","FACC2YI   ","FACC2ZI   ","FACC3XI   ", &
                               "FACC3YI   ","FACC3ZI   ","FACC4XI   ","FACC4YI   ","FACC4ZI   ","FACC5XI   ","FACC5YI   ", &
                               "FACC5ZI   ","FACC6XI   ","FACC6YI   ","FACC6ZI   ","FACC7XI   ","FACC7YI   ","FACC7ZI   ", &
                               "FACC8XI   ","FACC8YI   ","FACC8ZI   ","FACC9XI   ","FACC9YI   ","FACC9ZI   ","FACCMCF1XI", &
                               "FACCMCF1YI","FACCMCF1ZI","FACCMCF2XI","FACCMCF2YI","FACCMCF2ZI","FACCMCF3XI","FACCMCF3YI", &
                               "FACCMCF3ZI","FACCMCF4XI","FACCMCF4YI","FACCMCF4ZI","FACCMCF5XI","FACCMCF5YI","FACCMCF5ZI", &
                               "FACCMCF6XI","FACCMCF6YI","FACCMCF6ZI","FACCMCF7XI","FACCMCF7YI","FACCMCF7ZI","FACCMCF8XI", &
                               "FACCMCF8YI","FACCMCF8ZI","FACCMCF9XI","FACCMCF9YI","FACCMCF9ZI","FDYNP1    ","FDYNP2    ", &
                               "FDYNP3    ","FDYNP4    ","FDYNP5    ","FDYNP6    ","FDYNP7    ","FDYNP8    ","FDYNP9    ", &
                               "FVEL1XI   ","FVEL1YI   ","FVEL1ZI   ","FVEL2XI   ","FVEL2YI   ","FVEL2ZI   ","FVEL3XI   ", &
                               "FVEL3YI   ","FVEL3ZI   ","FVEL4XI   ","FVEL4YI   ","FVEL4ZI   ","FVEL5XI   ","FVEL5YI   ", &
                               "FVEL5ZI   ","FVEL6XI   ","FVEL6YI   ","FVEL6ZI   ","FVEL7XI   ","FVEL7YI   ","FVEL7ZI   ", &
                               "FVEL8XI   ","FVEL8YI   ","FVEL8ZI   ","FVEL9XI   ","FVEL9YI   ","FVEL9ZI   ","WAVE1ELEV ", &
                               "WAVE1ELV1 ","WAVE1ELV2 ","WAVE2ELEV ","WAVE2ELV1 ","WAVE2ELV2 ","WAVE3ELEV ","WAVE3ELV1 ", &
                               "WAVE3ELV2 ","WAVE4ELEV ","WAVE4ELV1 ","WAVE4ELV2 ","WAVE5ELEV ","WAVE5ELV1 ","WAVE5ELV2 ", &
                               "WAVE6ELEV ","WAVE6ELV1 ","WAVE6ELV2 ","WAVE7ELEV ","WAVE7ELV1 ","WAVE7ELV2 ","WAVE8ELEV ", &
                               "WAVE8ELV1 ","WAVE8ELV2 ","WAVE9ELEV ","WAVE9ELV1 ","WAVE9ELV2 "/)
   INTEGER(IntKi), PARAMETER :: ParamIndxAry(117) =  (/ &                            ! This lists the index into AllOuts(:) of the allowed parameters ValidParamAry(:)
                                   FAcc1xi ,    FAcc1yi ,    FAcc1zi ,    FAcc2xi ,    FAcc2yi ,    FAcc2zi ,    FAcc3xi , &
                                   FAcc3yi ,    FAcc3zi ,    FAcc4xi ,    FAcc4yi ,    FAcc4zi ,    FAcc5xi ,    FAcc5yi , &
                                   FAcc5zi ,    FAcc6xi ,    FAcc6yi ,    FAcc6zi ,    FAcc7xi ,    FAcc7yi ,    FAcc7zi , &
                                   FAcc8xi ,    FAcc8yi ,    FAcc8zi ,    FAcc9xi ,    FAcc9yi ,    FAcc9zi , FAccMCF1xi , &
                                FAccMCF1yi , FAccMCF1zi , FAccMCF2xi , FAccMCF2yi , FAccMCF2zi , FAccMCF3xi , FAccMCF3yi , &
                                FAccMCF3zi , FAccMCF4xi , FAccMCF4yi , FAccMCF4zi , FAccMCF5xi , FAccMCF5yi , FAccMCF5zi , &
                                FAccMCF6xi , FAccMCF6yi , FAccMCF6zi , FAccMCF7xi , FAccMCF7yi , FAccMCF7zi , FAccMCF8xi , &
                                FAccMCF8yi , FAccMCF8zi , FAccMCF9xi , FAccMCF9yi , FAccMCF9zi ,     FDynP1 ,     FDynP2 , &
                                    FDynP3 ,     FDynP4 ,     FDynP5 ,     FDynP6 ,     FDynP7 ,     FDynP8 ,     FDynP9 , &
                                   FVel1xi ,    FVel1yi ,    FVel1zi ,    FVel2xi ,    FVel2yi ,    FVel2zi ,    FVel3xi , &
                                   FVel3yi ,    FVel3zi ,    FVel4xi ,    FVel4yi ,    FVel4zi ,    FVel5xi ,    FVel5yi , &
                                   FVel5zi ,    FVel6xi ,    FVel6yi ,    FVel6zi ,    FVel7xi ,    FVel7yi ,    FVel7zi , &
                                   FVel8xi ,    FVel8yi ,    FVel8zi ,    FVel9xi ,    FVel9yi ,    FVel9zi ,  Wave1Elev , &
                                 Wave1Elv1 ,  Wave1Elv2 ,  Wave2Elev ,  Wave2Elv1 ,  Wave2Elv2 ,  Wave3Elev ,  Wave3Elv1 , &
                                 Wave3Elv2 ,  Wave4Elev ,  Wave4Elv1 ,  Wave4Elv2 ,  Wave5Elev ,  Wave5Elv1 ,  Wave5Elv2 , &
                                 Wave6Elev ,  Wave6Elv1 ,  Wave6Elv2 ,  Wave7Elev ,  Wave7Elv1 ,  Wave7Elv2 ,  Wave8Elev , &
                                 Wave8Elv1 ,  Wave8Elv2 ,  Wave9Elev ,  Wave9Elv1 ,  Wave9Elv2 /)
   CHARACTER(ChanLen), PARAMETER :: ParamUnitsAry(117) =  (/ character(ChanLen) :: &  ! This lists the units corresponding to the allowed parameters
                               "(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)", &
                               "(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)", &
                               "(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)", &
                               "(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)", &
                               "(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)", &
                               "(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)", &
                               "(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)", &
                               "(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(m/s^2)","(Pa)   ","(Pa)   ", &
                               "(Pa)   ","(Pa)   ","(Pa)   ","(Pa)   ","(Pa)   ","(Pa)   ","(Pa)   ", &
                               "(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ", &
                               "(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ", &
                               "(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ", &
                               "(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m/s)  ","(m)    ", &
                               "(m)    ","(m)    ","(m)    ","(m)    ","(m)    ","(m)    ","(m)    ", &
                               "(m)    ","(m)    ","(m)    ","(m)    ","(m)    ","(m)    ","(m)    ", &
                               "(m)    ","(m)    ","(m)    ","(m)    ","(m)    ","(m)    ","(m)    ", &
                               "(m)    ","(m)    ","(m)    ","(m)    ","(m)    "/)


      ! Initialize values
   ErrStat = ErrID_None
   ErrMsg = ""
   InvalidOutput = .FALSE.


!   ..... Developer must add checking for invalid inputs here: .....

   do I=p%NWaveElev+1,9
      InvalidOutput(WaveElevi(I)) = .true.
      InvalidOutput(WaveElevi1(I))= .true.
      InvalidOutput(WaveElevi2(I))= .true.
   end do
   
   do I=p%NWaveKin+1,9
      InvalidOutput(FVel(   :,I))  = .true.
      InvalidOutput(FAcc(   :,I))  = .true.
      InvalidOutput(FDynP(    I))  = .true.
      InvalidOutput(FAccMCF(:,I))  = .true.
   end do
   
!   ................. End of validity checking .................


   !-------------------------------------------------------------------------------------------------
   ! Allocate and set index, name, and units for the output channels
   ! If a selected output channel is not available in this module, set error flag.
   !-------------------------------------------------------------------------------------------------

   ALLOCATE ( p%OutParam(0:p%NumOuts) , STAT=ErrStat2 )
   IF ( ErrStat2 /= 0_IntKi )  THEN
      CALL SetErrStat( ErrID_Fatal,"Error allocating memory for the SeaState OutParam array.", ErrStat, ErrMsg, RoutineName )
      RETURN
   ENDIF

      ! Set index, name, and units for the time output channel:

   p%OutParam(0)%Indx  = Time
   p%OutParam(0)%Name  = "Time"    ! OutParam(0) is the time channel by default.
   p%OutParam(0)%Units = "(s)"
   p%OutParam(0)%SignM = 1


      ! Set index, name, and units for all of the output channels.
      ! If a selected output channel is not available by this module set ErrStat = ErrID_Warn.

   DO I = 1,p%NumOuts

      p%OutParam(I)%Name  = OutList(I)

      Indx = FindValidChannelIndx(OutList(I), ValidParamAry, p%OutParam(I)%SignM)

      IF ( Indx > 0 ) THEN ! we found the channel name
         IF ( InvalidOutput( ParamIndxAry(Indx) ) ) THEN  ! but, it isn't valid for these settings
            p%OutParam(I)%Indx  = 0                 ! pick any valid channel (I just picked "Time=0" here because it's universal)
            p%OutParam(I)%Units = "INVALID"
            p%OutParam(I)%SignM = 0
         ELSE
            p%OutParam(I)%Indx  = ParamIndxAry(Indx)
            p%OutParam(I)%Units = ParamUnitsAry(Indx) ! it's a valid output
         END IF
      ELSE ! this channel isn't valid
         p%OutParam(I)%Indx  = 0                    ! pick any valid channel (I just picked "Time=0" here because it's universal)
         p%OutParam(I)%Units = "INVALID"
         p%OutParam(I)%SignM = 0                    ! multiply all results by zero

         CALL SetErrStat(ErrID_Warn, TRIM(p%OutParam(I)%Name)//" is not an available output channel.",ErrStat,ErrMsg,RoutineName)
      END IF

   END DO

   RETURN
END SUBROUTINE SetOutParam
!----------------------------------------------------------------------------------------------------------------------------------
!End of code generated by Matlab script
!**********************************************************************************************************************************
!====================================================================================================
SUBROUTINE SeaStOut_CloseOutput ( p, ErrStat, ErrMsg )
! This function cleans up after running the SeaState output module. It closes the output file,
! releases memory, and resets the number of outputs requested to 0.
!----------------------------------------------------------------------------------------------------

         ! Passed variables

   TYPE(SeaSt_ParameterType),  INTENT( INOUT ) :: p                    ! parameter data for this instance of the SeaState module        
   INTEGER,                       INTENT(   OUT ) :: ErrStat              ! a non-zero value indicates an error occurred           
   CHARACTER(*),                  INTENT(   OUT ) :: ErrMsg               ! Error message if ErrStat /= ErrID_None

         ! Internal variables
   INTEGER                                        :: ErrStat2


   !-------------------------------------------------------------------------------------------------
   ! Initialize error information
   !-------------------------------------------------------------------------------------------------
      
         
   ErrStat = ErrID_None         
   ErrMsg  = ""    
      

         ! Write the summary file header
   IF ( p%UnOutFile > -1 ) THEN   
      ! WRITE (p%UnOutFile,'(/,A/)', IOSTAT=ErrStat)  'This output file was closed on '//CurDate()//' at '//CurTime()//'.'
   
   !-------------------------------------------------------------------------------------------------
   ! Close our output file
   !-------------------------------------------------------------------------------------------------
      CLOSE( p%UnOutFile, IOSTAT = ErrStat2 )
      IF ( ErrStat2 /= 0 ) then
         ErrStat = ErrID_Severe
         ErrMsg  = ' Error closing SeaState output file.'
      END IF

   END IF
   
   RETURN

END SUBROUTINE SeaStOut_CloseOutput
!====================================================================================================

SUBROUTINE SeaStOut_WrSummaryFile(InitInp, InputFileData, p, ErrStat, ErrMsg )
      TYPE(SeaSt_InitInputType),       INTENT(IN   )  :: InitInp           !< Input data for initialization routine.
      TYPE(SeaSt_InputFile)    ,       INTENT(IN   )  :: InputFileData     !< Data from input file
      TYPE(SeaSt_ParameterType),       INTENT(IN   )  :: p                 !< Parameters      
      INTEGER(IntKi),                  INTENT(  OUT)  :: ErrStat           !< Error status of the operation
      CHARACTER(*),                    INTENT(  OUT)  :: ErrMsg            !< Error message if ErrStat /= ErrID_None

      
         ! Local variables
         
      CHARACTER(1024)                        :: SummaryName                         ! name of the SeaState summary file   
      INTEGER                                :: I                                   ! Generic counters
      REAL(SiKi)                             :: WaveNmbr                            ! Wavenumber of the current frequency component (1/meter)


      INTEGER(IntKi)                         :: ErrStat2                            ! local error status
      CHARACTER(ErrMsgLen)                   :: ErrMsg2                             ! local error message
      CHARACTER(*), PARAMETER                :: RoutineName = 'SeaStOut_WrSummaryFile'
   
      CHARACTER(64)                          :: Frmt
      INTEGER(IntKi)                         :: UnSum

      ErrStat = ErrID_None
      ErrMsg = ""
      
      
      
      IF ( .not. InputFileData%SeaStSum ) RETURN
      
         
      SummaryName = trim(InitInp%OutRootName)//'.sum'
      UnSum = -1

      !$OMP critical(fileopen_critical)
      CALL GetNewUnit( UnSum )
      CALL OpenFOutFile ( UnSum, SummaryName, ErrStat2, ErrMsg2 )
      !$OMP end critical(fileopen_critical)
         CALL SetErrStat(ErrStat2,ErrMsg2,ErrStat,ErrMsg,RoutineName)
         IF (ErrStat >=AbortErrLev) RETURN
      
      
            ! Write the summary file header
      
      WRITE (UnSum,'(/,A/)', IOSTAT=ErrStat2)  'This summary file was generated by '//trim(SeaSt_ProgDesc%Name)//' on '//CurDate()//' at '//CurTime()//'.'

      IF (InputFileData%WaveMod /= WaveMod_None .and. InputFileData%WaveMod /= WaveMod_ExtFull)  THEN
            
            WRITE( UnSum, '(1X,A61,F8.2,A4/)' )           'The Mean Sea Level to Still Water Level (MSL2SWL) Offset is :',p%WaveField%MSL2SWL,' (m)'
            WRITE( UnSum, '(1X,A15,F8.2,A8)' )            'Water Density: ', p%WaveField%WtrDens,                         '(kg/m^3)'
            WRITE( UnSum, '(1X,A15,F8.2,A20,F8.2,A19)' )  'Water Depth  : ', p%WaveField%WtrDpth,                         '(m) relative to MSL; ', &
                                                                             p%WaveField%EffWtrDpth,                      '(m) relative to SWL'
            WRITE( UnSum, '(1X,A15,F8.2,A20,F8.2,A19/)' ) 'Grid Z_Depth : ', InputFileData%Z_Depth - p%WaveField%MSL2SWL, '(m) relative to MSL; ', &
                                                                             InputFileData%Z_Depth,                       '(m) relative to SWL'
      end if
      
      Frmt  = '(1X,ES18.4e2,2x,ES18.4e2,2x,ES18.4e2,2x,ES18.4e2)'
      
         ! Write Kinematics grid point locations 
      WRITE( UnSum, '(1X,A31/)' )   'Wave Kinematics Grid Points (m)' 
      WRITE( UnSum, '(1X,A78)' )   '            Xi                  Yi  Zi relative to MSL  Z  relative to SWL'
      do i= 1, p%NGridPts
         ! NOTE: The Waves%WaveKinxi, yi, zi arrays hold all the grid point locations
         WRITE(UnSum,Frmt)   InputFileData%Waves%WaveKinGridxi(i),  InputFileData%Waves%WaveKinGridyi(i),  InputFileData%Waves%WaveKinGridzi(i) + p%WaveField%MSL2SWL,  InputFileData%Waves%WaveKinGridzi(i)
      end do
 
      !   ! Write User-requested Wave Kinematics locations
      WRITE( UnSum,  '(/)' ) 
      if (p%NWaveKin > 0) then
         WRITE( UnSum, '(1X,A51/)' )   'User-Requested Wave Kinematics Output Locations (m)'
         !  WRITE( UnSum,  '(/)' ) 
         WRITE( UnSum, '(2X,A84)' )   'Index                Xi                  Yi  Zi relative to MSL  Z  relative to SWL'
         Frmt  = '(1X,I5, 2X,ES18.4e2,2x,ES18.4e2,2x,ES18.4e2,2x,ES18.4e2)'
         do i= 1, p%NWaveKin
            ! NOTE: The InputFileData%WaveKinxi, yi, zi arrays hold the User-request kinematics output locations
            WRITE(UnSum,Frmt)   i, p%WaveKinxi(i),  p%WaveKinyi(i),  p%WaveKinzi(i) + p%WaveField%MSL2SWL,  p%WaveKinzi(i)
         end do
               
      else
         WRITE( UnSum, '(1X,A50)' )   'No User-Requested Wave Kinematics Output Channels'
      end if
            
         ! Write User-requested Wave Elevations
      WRITE( UnSum,  '(/)' ) 
      if (p%NWaveElev > 0) then
         WRITE( UnSum, '(1X,A50/)' )   'User-Requested Wave Elevation Output Locations (m)'
         ! WRITE( UnSum,  '(/)' ) 
         WRITE( UnSum, '(2X,A25)' )   'Index     Xi           Yi'
         Frmt  = '(1X,I5, 2X, ES11.4e2,2x,ES11.4e2)'
         do i= 1, p%NWaveElev
            WRITE(UnSum,Frmt)   i, p%WaveElevxi(i),  p%WaveElevyi(i)
         end do
               
      else
         WRITE( UnSum, '(1X,A50)' )   'No User-Requested Wave Elevation Output Channels'
      end if
      if (p%NumOuts > 0) then
         WRITE( UnSum, '(//1X,A/)' )   'Requested Output Channels'
         do i = 1, p%NumOuts
            WRITE( UnSum, '(4X,A)' ) p%OutParam(I)%Name
         end do
      end if
         
      IF (InputFileData%WaveMod /= WaveMod_ExtFull)  THEN
            ! Write wave kinematics at (0,0)
         WRITE( UnSum,  '(/)' )         
         WRITE( UnSum, '(1X,A28/)' )   'Wave Kinematics DFT at (0,0)'
         !  WRITE( UnSum,  '(/)' )
         WRITE( UnSum, '(1X,A10,2X,A14,2X,A14,2X,A14,2X,A19,2X,A19)' )  &
                  '  index ', '    k    ', '   Omega     ', '   Direction  ', 'REAL(DFT{WaveElev})','IMAG(DFT{WaveElev})'
         WRITE( UnSum, '(1X,A10,2X,A14,2X,A14,2X,A14,2X,A19,2X,A19)' )  &
                  '   (-)  ', '  (1/m)  ', '   (rad/s)   ', '     (deg)    ', '       (m)         ','       (m)         '

         ! Write the data
         DO I = -1*p%WaveField%NStepWave2+1, p%WaveField%NStepWave2
            WaveNmbr   = WaveNumber ( I*p%WaveField%WaveDOmega, InitInp%Gravity, p%WaveField%EffWtrDpth )
            WRITE( UnSum, '(1X,I10,2X,ES14.5,2X,ES14.5,2X,ES14.5,2X,ES14.5,7X,ES14.5)' ) I, WaveNmbr, I*p%WaveField%WaveDOmega, &
                     p%WaveField%WaveDirArr(ABS(I)),  p%WaveField%WaveElevC0( 1,ABS(I ) ) ,   p%WaveField%WaveElevC0( 2, ABS(I ) )*SIGN(1,I)
         END DO
      END IF
         
      
         ! Close the summary file
      WRITE (UnSum,'(/,A/)', IOSTAT=ErrStat2)  'This summary file was closed on '//CurDate()//' at '//CurTime()//'.'
      IF (ErrStat2 /= 0) THEN
         CALL SetErrStat(ErrID_Severe,'Problem writing to summary file.',ErrStat,ErrMsg,RoutineName)
      END IF
   
      ! Close the file
   
      CLOSE( UnSum, IOSTAT=ErrStat2 )
      
END SUBROUTINE SeaStOut_WrSummaryFile

!====================================================================================================
END MODULE SeaState_Output
